#pragma once

#include <iostream>
#include <fstream>
#include <cstdio>
#include <string>
#include <ctime>
#include <cstdarg>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
#include <mutex>

namespace JsonRpc
{

    bool gIsSave = false;
    const std::string logname = "log.txt";

    // 日志等级
    enum Level
    {
        DEBUG = 0,
        INFO,
        WARNING,
        ERROR,
        FATAL
    };
    // 默认打印等级
    Level IsLevel = DEBUG;

    // 设置日志打印等级
    // void SetPrintLevel(Level level)
    // {
    //     IsLevel = level;
    // }

    // 写入文件
    void SaveFile(const std::string &filename, const std::string &message)
    {
        std::ofstream out(filename, std::ios::app);
        if (!out.is_open())
        {
            return;
        }
        out << message;
        out.close();
    }

    std::string LevelToString(int level)
    {
        switch (level)
        {
        case DEBUG:
            return "Debug";
        case INFO:
            return "Info";
        case WARNING:
            return "Warning";
        case ERROR:
            return "Error";
        case FATAL:
            return "Fatal";
        default:
            return "Unknown";
        }
    }

    std::string GetTimeString()
    {
        time_t curr_time = time(nullptr);
        struct tm *format_time = localtime(&curr_time);
        if (format_time == nullptr)
            return "None";
        char time_buffer[1024];
        snprintf(time_buffer, sizeof(time_buffer), "%d-%d-%d %d:%d:%d",
                 format_time->tm_year + 1900,
                 format_time->tm_mon + 1,
                 format_time->tm_mday,
                 format_time->tm_hour,
                 format_time->tm_min,
                 format_time->tm_sec);
        return time_buffer;
    }

    // 日志格式
    // 日志等级 时间 代码所在的文件名/行数 日志的内容
    void LogMessage(std::string filename, int line, bool issave, int level, const char *format, ...)
    {
        if (level < IsLevel)
            return;

        std::string levelstr = LevelToString(level);
        std::string timestr = GetTimeString();
        pid_t selfid = getpid();

        char buffer[4096];
        va_list arg;
        va_start(arg, format);
        vsnprintf(buffer, sizeof(buffer), format, arg);
        va_end(arg);

        std::string message = "[" + timestr + "]" + "[" + levelstr + "]" +
                              "[" + std::to_string(selfid) + "]" +
                              "[" + filename + "]" + "[" + std::to_string(line) + "] " + buffer;

        // 互斥访问
        std::mutex mtx;
        std::lock_guard<std::mutex> lck(mtx);

        if (!issave)
        {
            std::cout << message;
        }
        else
        {
            SaveFile(logname, message);
        }
    }

// C99新特性__VA_ARGS__
#define LOG(level, format, ...)                                                \
    do                                                                         \
    {                                                                          \
        JsonRpc::LogMessage(__FILE__, __LINE__, JsonRpc::gIsSave, level, format, ##__VA_ARGS__); \
    } while (0)

// 写入文件
#define EnableFile()             \
    do                           \
    {                            \
        JsonRpc::gIsSave = true; \
    } while (0)

// 写入显示器
#define EnableScreen()            \
    do                            \
    {                             \
        JsonRpc::gIsSave = false; \
    } while (0)

// 设置打印等级
#define EnableLevel(level)        \
    do                            \
    {                             \
        JsonRpc::IsLevel = level; \
    } while (0)

}